package cn.edu.jsu.zjj.controller;


import cn.edu.jsu.zjj.annotation.Type;
import cn.edu.jsu.zjj.common.DeleteRequest;
import cn.edu.jsu.zjj.common.result.PageResult;
import cn.edu.jsu.zjj.common.result.Result;
import cn.edu.jsu.zjj.constant.MessageConstant;
import cn.edu.jsu.zjj.exception.BaseException;
import cn.edu.jsu.zjj.exception.ThrowUtils;
import cn.edu.jsu.zjj.mapper.SysDataMapper;
import cn.edu.jsu.zjj.model.dto.data.DataAddRequst;
import cn.edu.jsu.zjj.model.dto.filter.DocuFilterRequest;
import cn.edu.jsu.zjj.model.entity.Docu;
import cn.edu.jsu.zjj.model.entity.SysData;

import cn.edu.jsu.zjj.model.entity.SysHeader;
import cn.edu.jsu.zjj.model.utils.ZipUtils;
import cn.edu.jsu.zjj.service.DocuService;
import cn.edu.jsu.zjj.service.ISysDataService;
import cn.edu.jsu.zjj.service.ISysHeaderService;
import cn.edu.jsu.zjj.service.UserService;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import kotlin.Pair;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 数据相关接口
 */
@RestController
@RequestMapping("/data")
@Api(tags = "数据相关接口")
@Slf4j
public class SysDataController {
    @Autowired
    private ISysDataService sysDataService;
    @Autowired
    private SysDataMapper sysDataMapper;
    @Autowired
    private UserService userService;
    @Autowired
    private DocuService docuService;
    @Autowired
    private ISysHeaderService sysHeaderService;
    /**
     * 根据资料id修改数据（包括增删改）,防止已经设置isDelete=1的数据被修改
     * @param dataAddRequst
     * @return
     */

    @ApiOperation("添加数据")
    @PostMapping("/add")
    public Result add(@RequestBody DataAddRequst dataAddRequst) {
        log.info("添加数据：{}", dataAddRequst);
        SysData sysData = new SysData();
        BeanUtils.copyProperties(dataAddRequst, sysData);
        sysData.setCreateTime(LocalDateTime.now());
        sysData.setUpdateTime(LocalDateTime.now()); // 设置更新时间
        sysData.setUserName(userService.getLoginUser().getName());
        sysData.setUserId(userService.getLoginUser().getId());
        boolean result = sysDataService.save(sysData);
        ThrowUtils.throwIf(!result, MessageConstant.OPERATION_ERROR);
        return Result.success("数据添加成功", sysData); // 返回添加成功信息和添加后的数据
    }

    @NotNull
    private Result getResult(SysData sysData) {
        sysData.setUpdateTime(LocalDateTime.now());
        sysData.setUserName(userService.getLoginUser().getName());
        sysData.setUserId(userService.getLoginUser().getId());
        boolean result = sysDataService.save(sysData);
        ThrowUtils.throwIf(!result, MessageConstant.OPERATION_ERROR);
        return Result.success("数据修改成功",sysData); // 返回修改成功信息和修改后的数据
    }

    @ApiOperation("根据资料数据id修改数据（包括删改）")
    @PostMapping
    public Result save(@RequestBody DataAddRequst dataAddRequst) {
        // 修改资料数据时，判断数据是否已被删除
        if (dataAddRequst.getId() != null && dataAddRequst.getId() > 0) {
            // 存在id则判断当前数据是否为已删除
            LambdaQueryWrapper<SysData> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysData::getId, dataAddRequst.getId());
            queryWrapper.ne(SysData::getIsDelete, 1);
            SysData sysData1 = sysDataMapper.selectOne(queryWrapper);
            if (sysData1.getIsDelete() == 1) {
                return Result.error("资料不存在");
            }
        }

        log.info("根据资料id修改数据（包括增删改）：{}", dataAddRequst);
        SysData sysData = new SysData();
        BeanUtils.copyProperties(dataAddRequst, sysData);
        return getResult(sysData);
    }

    /**
     * 修改数据
     * @param dataAddRequst
     * @return
     */
    @ApiOperation("修改数据")
    @PutMapping
    public Result update(@RequestBody DataAddRequst dataAddRequst) {
        log.info("修改数据：{}", dataAddRequst);
        SysData sysData = new SysData();
        sysData.setUpdateTime(LocalDateTime.now());
        sysData.setUserName(userService.getLoginUser().getName());
        sysData.setUserId(userService.getLoginUser().getId());
        BeanUtils.copyProperties(dataAddRequst, sysData);
        boolean result = sysDataService.updateById(sysData);
        ThrowUtils.throwIf(!result, MessageConstant.OPERATION_ERROR);
        return Result.success("数据修改成功",sysData); // 返回修改成功信息和修改后的数据
    }


    @ApiOperation("导出选择的数据")
    @PostMapping(value = "/select")
    public void select(HttpServletResponse response,@ModelAttribute JSONObject requestParams,@RequestBody List<Long> ids) throws IOException {
        List<SysHeader> headers = new ArrayList<>();
        List<SysData> sysDataList = new ArrayList<>();
        Long id ;
        if(!ids.isEmpty()){
            LambdaQueryWrapper<SysData> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysData::getIsDelete, 0);
            queryWrapper.in(SysData::getId, ids);
            sysDataList = sysDataService.list(queryWrapper);
            LambdaQueryWrapper<SysHeader> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(SysHeader::getIsDelete, 0);
            headers = sysHeaderService.list(queryWrapper1);
            id = sysDataList.get(0).getDocuId();
        }else{
            id = requestParams.getLong("docuId");
            //查询表头
            headers = sysHeaderService.list(new LambdaQueryWrapper<SysHeader>()
                    .eq(SysHeader::getDocuId, id)
                    .orderByAsc(SysHeader::getSort));
            // 查询筛选的表单数据
            QueryWrapper<SysData> queryWrapper = new QueryWrapper<>();
            // 动态拼接查询条件，根据请求参数中的key进行筛选
            for (String key : requestParams.keySet()) {
                if (key.startsWith("key")) {
                    String value = requestParams.getStr(key);
                    if (value != null && !value.isEmpty()) {
                        queryWrapper.like("JSON_EXTRACT(data, '$." + key + "')", value);
                    }
                }
            }
            // 排除已删除的数据，docu_id字段等于提供的资料ID
            queryWrapper.eq("is_delete", 0);
            queryWrapper.eq("docu_id", id);
            sysDataList = sysDataService.list(queryWrapper);
        }
        //处理数据
        List<String> headList = new ArrayList<>();
        List<String> sortList = new ArrayList<>();
        List<List<Object>> dataList = new ArrayList<>();
        for (SysHeader header : headers) {
            headList.add(header.getName());
            sortList.add(header.getHeaderKey());
        }
        //TODO: 添加附件列
        headList.add("附件名称");



        //文件名，二进制数组的键值对
        List<String> fileNameList = new ArrayList<>();
        List<byte[]> bytesList = new ArrayList<>();

        for (SysData sysData : sysDataList) {
            JSONObject jsonObject = JSONUtil.parseObj(sysData.getData());
            List<Object> objectList = new ArrayList<>();

            for (String sort : sortList) {
                boolean found = false;
                for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                    if (Objects.equals(entry.getKey(), sort)) {
                        objectList.add(entry.getValue());
                        found = true;
                        break; // 找到后跳出内层循环
                    }
                }
                if (!found) {
                    objectList.add(null); // 如果没有找到对应的 key，添加 null
                }
            }

            objectList.add(sysData.getFileName());
            dataList.add(objectList);

            // 附件
            String fileUrl = sysData.getFileUrl();
            if (StringUtils.isNotEmpty(fileUrl)) {
                ZipUtils.urlToByte(sysData.getFileUrl());
                fileNameList.add(ZipUtils.fileName);
                bytesList.add(ZipUtils.urlBytes);
            }
        }




        // 将文件名和二进制数组的键值对封装成Pair对象
        Pair<List<String>, List<byte[]>> pair = new Pair<>(fileNameList, bytesList);

        LambdaQueryWrapper<Docu> docuQueryWrapper = new LambdaQueryWrapper<>();
        docuQueryWrapper.eq(Docu::getId, id);
        Docu docu = docuService.getOne(docuQueryWrapper);
        String excelName = docu.getName();
        // 调用工具类进行导出
        ZipUtils.main(response, headList, dataList,pair,excelName,null);

    }

    /**
     * 根据资料id查询数据, 排除已删除数据
     * 该方法通过接收一个JSON对象，其中包含分页信息和查询条件，来查询特定资料ID的相关数据
     * 主要用于Web接口，通过POST请求方式提交查询参数
     *
     * @param requestParams 请求参数，包含分页信息和查询条件
     * @return 返回查询结果，包括总记录数和当前页数据
     */
    @ApiOperation("根据资料id查询数据")
    @PostMapping("/page")
    public Result getById(@RequestBody JSONObject requestParams) {
        // 记录查询日志，包括查询条件
        log.info("根据资料id查询数据：{}", requestParams);

        // 获取分页参数和查询条件
        long size = requestParams.getLong("pageSize");
        int current = requestParams.getInt("current");
        long docuId = requestParams.getLong("docuId");

        // 校验资料ID是否有效
        if (docuId <= 0) {
            throw new BaseException(MessageConstant.PARAMS_ERROR);
        }

        // 初始化查询条件封装对象
        QueryWrapper<SysData> queryWrapper = new QueryWrapper<>();


        List<String> userRoleList = userService.getLoginUser().getRoles();
        // 教师角色，只能查看自己的资料
        if (userRoleList.contains("user")) {
            queryWrapper.eq("user_id", userService.getLoginUser().getId());
        }

        // 动态拼接查询条件，根据请求参数中的key进行筛选
        for (String key : requestParams.keySet()) {
            if (key.startsWith("key")) {
//                // 使用MySQL的JSON_EXTRACT函数进行JSON数据的筛选
//                queryWrapper.apply("JSON_EXTRACT(data, '$." + key + "') = '" + requestParams.getStr(key) + "'");
                String value = requestParams.getStr(key);
                if (value != null && !value.isEmpty()) {
                    queryWrapper.like("JSON_EXTRACT(data, '$." + key + "')", value);
                }
            }
        }

        // 排除已删除的数据，docu_id字段等于提供的资料ID
        queryWrapper.eq("is_delete", 0);
        queryWrapper.eq("docu_id", docuId);

        // 执行分页查询
        Page<SysData> page = sysDataService.page(new Page<>(current, size), queryWrapper);

        // 返回查询结果
        return Result.success(new PageResult(page.getTotal(), page.getRecords()));
    }

    /**
     * 根据id查询数据,防止已经设置isDelete=1的数据被查询到
     *
     * @param id
     * @return
     */
    @ApiOperation("根据id查询数据")
    @GetMapping("/{id}")
    public Result getById(@PathVariable Long id) {
        if (id <= 0) {
            throw new BaseException(MessageConstant.PARAMS_ERROR);
        }
        LambdaQueryWrapper<SysData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysData::getId, id)
                .ne(SysData::getIsDelete, 1);
        SysData sysData = sysDataService.getOne(queryWrapper);
        ThrowUtils.throwIf(sysData == null, MessageConstant.NOT_FOUND_ERROR);
        return Result.success(sysData);
    }

    /**
     * 删除数据
     * @param deleteRequest
     * @return
     */
    @Type("删除数据")
    @PostMapping("/delete")
    @ApiOperation("删除数据")
    public Result deleteData(@RequestBody DeleteRequest deleteRequest) {
        log.info("删除数据：{}", deleteRequest);
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BaseException(MessageConstant.PARAMS_ERROR);
        }
        return Result.success(sysDataService.removeById(deleteRequest.getId()));
    }

    @PostMapping("/dynamicHeadExport/{id}")
    @ApiOperation("导出动态表头")
    public void dynamicHeadExport(@PathVariable Long id, HttpServletResponse response) throws IOException {
        sysDataService.dynamicHeadExport(id, response);
    }

    /**
     * 导出动态表zip文件的方法，返回响应数据到客户端。
     *
     * @param response HttpServletResponse对象，用于构建响应
     * @param id      动态表的ID
     * @throws IOException 处理输入输出异常
     */
    @ApiOperation("导出动态表zip文件")
    @PostMapping(value = "/export/{id}")
    public void export(HttpServletResponse response,@PathVariable Long id) throws IOException {
        List<SysHeader> headers = sysHeaderService.list(new LambdaQueryWrapper<SysHeader>()
                .eq(SysHeader::getDocuId, id)
                .orderByAsc(SysHeader::getSort));
        List<String> headList = new ArrayList<>();
        List<String> sortList = new ArrayList<>();
        for (SysHeader header : headers) {
            headList.add(header.getName());
            sortList.add(header.getHeaderKey());
        }
        //TODO: 添加附件列
        headList.add("附件名称");
        List<List<Object>> dataList = new ArrayList<>();

        List<String> userRoleList = userService.getLoginUser().getRoles();


        // 获取动态数据
        LambdaQueryWrapper<SysData> queryWrapper1 = new LambdaQueryWrapper<SysData>();
        queryWrapper1.eq(SysData::getDocuId, id);
        queryWrapper1.ne(SysData::getIsDelete, 1);
        // 教师角色，只能查看自己的资料
        if (userRoleList.contains("user")) {
            queryWrapper1.eq(SysData::getUserId, userService.getLoginUser().getId());
        }
        List<SysData> sysDataList = sysDataService.list(queryWrapper1);

        //文件名，二进制数组的键值对
        List<String> fileNameList = new ArrayList<>();
        List<byte[]> bytesList = new ArrayList<>();

        for (SysData sysData : sysDataList) {
            JSONObject jsonObject = JSONUtil.parseObj(sysData.getData());
            List<Object> objectList = new ArrayList<>();

            for (String sort : sortList) {
                boolean found = false;
                for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                    if (Objects.equals(entry.getKey(), sort)) {
                        objectList.add(entry.getValue());
                        found = true;
                        break; // 找到后跳出内层循环
                    }
                }
                if (!found) {
                    objectList.add(null); // 如果没有找到对应的 key，添加 null
                }
            }

            objectList.add(sysData.getFileName());
            dataList.add(objectList);

            // 附件
            String fileUrl = sysData.getFileUrl();
            if (StringUtils.isNotEmpty(fileUrl)) {
                ZipUtils.urlToByte(sysData.getFileUrl());
                fileNameList.add(ZipUtils.fileName);
                bytesList.add(ZipUtils.urlBytes);
            }
        }




        // 将文件名和二进制数组的键值对封装成Pair对象
        Pair<List<String>, List<byte[]>> pair = new Pair<>(fileNameList, bytesList);

        LambdaQueryWrapper<Docu> docuQueryWrapper = new LambdaQueryWrapper<>();
        docuQueryWrapper.eq(Docu::getId, id);
        Docu docu = docuService.getOne(docuQueryWrapper);
        String excelName = docu.getName();
        // 调用工具类进行导出
        ZipUtils.main(response, headList, dataList,pair,excelName,null);

    }


}
